AOP之@AspectJ技术原理详解


一、AOP

AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑
各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

1.1 主要功能

日志记录,性能统计,安全控制,事务处理,异常处理等等。

1.2 主要目标

将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变
这些行为的时候不影响业务逻辑的代码。

1.3 适用对象

比较大型的项目,而且迭代较快,使用OOP太消耗内力。
有日志、性能、安全、异常处理等横切关注点需求。

1.4 AOP与OOP的关系

OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。但是也有它的缺点,最明显的就是关注点聚焦时,面向对象无法简单的解决这个问题,一个关注点是面向所有而不是单一的类,不受类的边界的约束,因此OOP无法将关注点聚焦来解决,只能分散到各个类中。
AOP(面向切面编程)则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
AOP并不是与OOP对立的,而是为了弥补OOP的不足。OOP解决了竖向的问题,AOP则解决横向的问题。因为有了AOP我们的调试和监控就变得简单清晰。它们之间的关系如下图所示:

这里写图片描述

1.4.1 对比一——单一横切关注点
这里写图片描述

这里写图片描述

1.4.2 对比二——多横切关注点
这里写图片描述

结论:
这里写图片描述


二、Android中使用@AspectJ

AspectJ 意思就是Java的Aspect,Java的AOP。它其实不是一个新的语言,它的核心是ajc(编译器)\weaver(织入器)。

  • ajc编译器:基于Java编译器之上的,它是用来编译.aj文件,aspectj在Java编译器的基础上增加了一些它自己的关键字和方法。因此,ajc也可以编译Java代码。
  • weaver织入器:为了在java编译器上使用AspectJ而不依赖于Ajc编译器,aspectJ 5出现了@AspectJ,使用注释的方式编写AspectJ代码,可以在任何Java编译器上使用。

由于AndroidStudio默认是没有ajc编译器的,所以在Android中使用@AspectJ来编写(包括SpringAOP也是如此)。它在代码的编译期间扫描目标程序,根据切点(PointCut)匹配,将开发者编写的Aspect程序编织(Weave)到目标程序的.class文件中,对目标程序作了重构(重构单位是JoinPoint),目的就是建立目标程序与Aspect程序的连接(获得执行的对象、方法、参数等上下文信息),从而达到AOP的目的。

2.1 Gradle 配置示例

要引入AspectJ到Android工程中,最重要的就是两个包:

//在buildscript中添加该编织器,gradle构建时就会对class文件进行编织
classpath 'org.aspectj:aspectjweaver:1.8.9'
//在dependencies中添加该依赖,提供@AspectJ语法
compile 'org.aspectj:aspectjrt:1.8.9'

此外还有一个工具包,用于Gradle构建时进行打日志等操作:

//在buildscript中添加该工具包,在构建工程的时候执行一些任务:打日志等
classpath 'org.aspectj:aspectjtools:1.8.9'import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

//打印gradle日志
android.libraryVariants.all { variant ­>
LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)
  JavaCompile javaCompile = variant.javaCompile
  javaCompile.doLast {
  String[] args = ["­showWeaveInfo",
     "­1.5",
     "­inpath", javaCompile.destinationDir.toString(),
     "­aspectpath", javaCompile.classpath.asPath,
     "­d", javaCompile.destinationDir.toString(),
     "­classpath", javaCompile.classpath.asPath,
     "­bootclasspath", 
     project.android.bootClasspath.join(
     File.pathSeparator)]
  MessageHandler handler = new MessageHandler(truenew Main().run(args, handler)
  def log = project.logger
  for (IMessage message : handler.getMessages(null, true)) {
  switch (message.getKind()) {
    case IMessage.ABORT:
    case IMessage.ERROR:
    case IMessage.FAIL:
      log.error message.message, message.thrown
    break;
    case IMessage.WARNING:
    case IMessage.INFO:
      log.info message.message, message.thrown
    break;
    case IMessage.DEBUG:
      log.debug message.message, message.thrown
    break;
   }
 }
}
}

附:美团RoboAspectJ

buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'com.meituan.gradle:roboaspectj:0.9.2'
classpath 'jaop.gradle.plugin:gradle­plugin:1.0.2'
}
// Exclude the version that the android plugin depends on.
configurations.classpath.exclude group: 'com.android.tools.external.lombok'
}

配置参数

// AspectJ
aspectj {
disableWhenDebug true
javartNeeded true
// 排除不需要AOP扫描的包
exclude group: 'xxxx', module: 'xxxx'
compileOptions {
defaultJavaVersion = JavaVersion.VERSION_1_7
}
}

2.2 基本概念

2.2.1 切面——Aspect

实现了cross­cutting功能,是针对切面的模块。最常见的是logging模块、方法执行耗时模块,这样,程序按功能被分为好几层,如果按传统的继承的话,商业模型继承日志模块的话需要插入修改的地方太多,而通过创建一个切面就可以使用AOP来实现相同的功能了,我们可以针对不同的需求做出不同的切面。

2.2.2 连接点——JoinPoint

连接点是切面插入应用程序的地方,该点能被方法调用,而且也会被抛出意外。连接点是应用程序提供给切面插入的地方,可以添加新的方法。比如:我们的切点可以认为是findInfo(String)方法。
AspectJ将面向对象的程序执行流程看成是JoinPoint的执行链,每一个JoinPoint是一个单独的闭包,在执行的时候将上下文环境赋予闭包执行方法体逻辑。
下面列表上的是被AspectJ认为是joinpoint的:
这里写图片描述

2.2.3 切点——PointCut

切点的声明决定需要切割的JoinPoint的集合,就结果上来说,它是JoinPoint的一个实际子集合。
pointcut可以控制你把哪些advice应用于jointpoint上去,通常通过正则表达式来进行匹配应用,决定了那个jointpoint会获得通知。分为call、execution、target、this、within等关键字,含义下面会附图。
1.直接针对JoinPoint的选择
pointcuts中最常用的选择条件和Joinpoint的类型密切相关,比如图5:
这里写图片描述

2.间接针对JPoint的选择
除了根据前面提到的Signature信息来匹配JPoint外,AspectJ还提供其他一些选择方法来选择JPoint。比如某个类中的所有JPoint,每一个函数执行流程中所包含的JPoint。
特别强调,不论什么选择方法,最终都是为了找到目标的JPoint。
表2列出了一些常用的非JPoint选择方法:
这里写图片描述

3.匹配规则
(1)类型匹配语法
首先让我们来了解下AspectJ类型匹配的通配符:

*:匹配任何数量字符;
..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
+:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
AspectJ使用 且(&&)、或(||)、非(!)来组合切入点表达式。

(2)匹配模式
call(<注解?> <修饰符?> <返回值类型> <类型声明?>.<方法名>(参数列表) <异常列表>?)

  • 精确匹配
//表示匹配 com.davidkuper.MainActivity类中所有被@Describe注解的public void方法。
@Pointcut("call(@Describe public void com.davidkuper.MainActivity.init(Context))")
public void pointCut(){}
  • 单一模糊匹配
//表示匹配 com.davidkuper.MainActivity类中所有被@Describe注解的public void方法。
@Pointcut("call(@Describe public void com.davidkuper.MainActivity.*(..)) ")
public <
  • 19
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
内容为J2EE应用开发详解中的源代码 第1章 Java Web应用开发简介 1   1.1 Java EE应用概述 1   1.2 Java EE概念 1   1.2.1 Java EE多层模型 1   1.2.2 Java EE体系结构 2   1.3 Java EE的核心API与组件 4   1.4 Web服务器和应用服务器 13   1.5 小结 16   第2章 建立开发平台 17   2.1 构建开发环境 17   2.1.1 安装JDK 17   2.1.2 安装Tomcat 21   2.1.3 安装Eclipse 23   2.2 配置开发环境 23   2.3 小结 26   第3章 Java的反射机制 27   3.1 Java反射API 27   3.2 加载类的实例 29   3.2.1 加载class对象的两种方式 29   3.2.2 Class.forName()加载类的实例 30   3.2.3 loadClass获得类的实例 31   3.3 操作类的字段 31   3.3.1 获取对象的属性 31   3.4 操作类的方法 34   3.4.1 运行时调用对象的方法 34   3.4.2 无参构造函数 36   3.4.3 带参构造函数 37   3.5 动态代理 39   3.6 反射机制在Hibernate中的应用 42   3.7 小结 46   第4章 Servlet技术 47   4.1 Servlet简介 47   4.1.1 Servlet的特点 47   4.1.2 Servlet的优势 48   4.1.3 Servlet的工作过程 49   4.1.4 Servlet的生命周期 50   4.2 开发和部署一个简单的Servlet 51   4.3 Servlet常用API介绍 53   4.3.1 Servlet实现相关 54   4.3.2 Servlet配置相关 54   4.3.3 Servlet异常相关 55   4.3.4 请求和响应相关 55   4.3.5 会话跟踪 56   4.3.6 Servlet上下文 57   4.3.7 Servlet协作 57   4.3.8 Filter 58   4.4 使用Servlet处理客户端请求 58   4.5 会话跟踪 61   4.5.1 使用Cookie进行会话跟踪 61   4.5.2 使用URL重写进行会话跟踪 62   4.5.3 使用隐藏表单域进行会话跟踪 63   4.6 小结 65   第5章 JSP技术 67   5.1 JSP简介 67   5.2 JSP页面的结构 68   5.3 脚本元素 68   5.3.1 Scriptlet元素 69   5.3.2 Expression元素 69   5.3.3 Declaration元素 70   5.4 指令 73   5.4.1 page指令 73   5.4.2 include指令 75   5.5 动作 76   5.5.1 Resource动作 76   5.5.2 JavaBean动作 78   5.6 隐式对象 78   5.6.1 request对象 78   5.6.2 response对象 78   5.6.3 application对象 78   5.6.4 out对象 79   5.6.5 page对象 79   5.6.6 session对象 79   5.6.7 exception对象 80   5.6.8 pageContext对象 80   5.6.9 config对象 80   5.7 JSP自定义标签 81   5.8 小结 84   第6章 XML、CSS和XSLT 85   6.1 XML 85   6.1.1 什么是XML 85   6.1.2 XML的产生 85   6.1.3 XML的用途 86   6.1.4 XML元素 87   6.1.5 XML属性 87   6.1.6 XML语法规则 89   6.1.7 XML检验 91   6.2 CSS 92   6.3 XSLT 94   6.4 小结 96   第7章 Ajax简介 97   7.1 Ajax简介 97   7.2 Ajax技术核心 100   7.2.1 XMLHttpRequest对象的常用方法 100   7.2.2 标准的XMLHttpRequest属性 101   7.3 一个简单的Ajax实例 101   7.4 小结 104   第8章 Struts2框架 105   8.1 Web应用的发展 105   8.2 Struts2的起源和体系结构 106   8.3 Struts2核心部分详解 108   8.3.1 核心控制器FilterDispatcher 108   8.3.2 业务逻辑控制器Action 111   8.3.3 业务逻辑组件 116   8.3.4 Struts2表示层 118   8.3.5 Struts2配置文件 119   8.4 Action的配置方式 121   8.4.1 动态方法调用 121   8.4.2 设置action元素的method属性 122   8.4.3 使用通配符配置action 122   8.4.4 默认action 123   8.5 拦截器Interceptor 123   8.5.1 拦截器的定义 124   8.5.2 拦截器的实现原理 124   8.5.3 Struts2的内置拦截器 124   8.5.4 拦截器的配置和使用 125   8.5.5 自定义拦截器 126   8.6 一个简单的Struts2应用 130   8.7 小结 140   第9章 JSF 141   9.1 JSF技术简介 141   9.1.1 JSF与MVC模式 141   9.1.2 JSF应用程序配置 142   9.2 一个简单的JSF应用 142   9.2.1 JSF应用程序开发步骤 143   9.2.2 用户登录实例 143   9.3 JSF应用程序架构 147   9.3.1 JSF请求处理生命周期 147   9.3.2 JSF事件驱动模型 148   9.3.3 JSF导航模型 149   9.4 JSF的组成 152   9.4.1 UI组件 152   9.4.2 JSF标签 154   9.5 统一EL 156   9.5.1 表达式和函数 156   9.5.2 操作符 157   9.5.3 保留字 158   9.5.4 内置对象 158   9.6 Backing Bean 158   9.7 创建自定义组件 162   9.8 小结 164   第10章 JavaBean 165   10.1 JavaBean简介 165   10.1.1 JavaBean的特点 166   10.1.2 JavaBean的元素及属性 167   10.1.3 JavaBean的分类 168   10.2 创建JavaBean 168   10.2.1 JavaBean的规格说明 168   10.2.2 创建一个简单的JavaBean 168   10.3 在JSP中使用JavaBean 169   10.4 使用JavaBean连接数据库 172   10.5 小结 177   第11章 EJB 179   11.1 EJB简介 179   11.1.1 EJB的特点 179   11.1.2 EJB类型与组成 180   11.1.3 EJB 3.0的新特性 181   11.2 元数据注释和部署描述符 181   11.2.1 元数据注释 181   11.2.2 部署描述符 182   11.3 EJB支持JNDI 183   11.3.1 JNDI的概念 183   11.3.2 使用JNDI 186   11.4 会话Bean 191   11.4.1 会话Bean的分类 191   11.4.2 会话Bean的组成 195   11.4.3 会话Bean的生命周期 196   11.4.4 创建无状态会话Bean 197   11.4.5 创建有状态会话Bean 198   11.5 消息驱动Bean和消息服务 199   11.5.1 JMS 200   11.5.2 消息驱动Bean的生命周期 202   11.5.3 创建消息驱动Bean 202   11.6 实体Bean 203   11.6.1 实体Bean的特性 204   11.6.2 实体Bean的分类及组成 204   11.6.3 EJB 3.0中的实体Bean 206   11.7 EJB事务 208   11.7.1 基于容器管理事务 209   11.7.2 基于Bean管理的事务 210   11.8 EJB拦截器 212   11.9 EJB定时服务 214   11.10 EJB安全管理 214   11.11 小结 216   第12章 RMI 217   12.1 RMI简介 217   12.1.1 RMI的架构 218   12.1.2 RMI的组成及实现 218   12.1.3 RMI的优点 219   12.2 一个RMI的简单实例 219   12.3 小结 226   第13章 Web服务概论 227   13.1 SOA简介 227   13.2 Web服务简介 229   13.3 Web服务的核心技术 230   13.3.1 SOAP 232   13.3.2 WSDL 235   13.3.3 UDDI 236   13.4 小结 236   第14章 CORBA 237   14.1 CORBA的需求 237   14.2 CORBA的架构 237   14.2.1 IDL 239   14.2.2 ORB 240   14.2.3 IIOP 241   14.2.4 BOA 241   14.3 CORBA服务 241   14.4 创建CORBA应用 243   14.5 CORBA与RMI 246   14.5.1 CORBA和RMI的区别 246   14.5.2 CORBA和RMI的互操作 247   14.6 小结 248   第15章 Spring框架 249   15.1 Spring 2.0的体系结构 249   15.2 Ioc容器 250   15.2.1 BeanFactory 250   15.2.2 ApplicationContext 252   15.2.3 Beans的生命周期过程 253   15.2.4 Beans的进阶管理 254   15.3 依赖注入 259   15.3.1 Constructor注入 259   15.3.2 Setter注入 261   15.3.3 Method注入 263   15.4 Spring AOP技术 266   15.4.1 装备(advices) 267   15.4.2 Spring AOP的传统用法 275   15.4.3 基于@AspectJ注释的AOP 277   15.4.4 基于aop命名空间的AOP 279   15.5 小结 282   第16章 数据库技术和JDBC技术 283   16.1 关系数据库和SQL 283   16.2 关系数据库的工作环境 284   16.3 基于JDBC的数据访问技术 285   16.3.1 JDBC概述 285   16.3.2 数据库驱动程序 287   16.3.3 使用JDBC查询数据库 291   16.3.4 常用的JDBC类和方法 294   16.3.5 数据库连接池中使用JDBC 297   16.4 小结 302   第17章 ORM与Java持久化机制 303   17.1 ORM概述 303   17.2 域模型 304   17.3 实体域对象的持久化模式 304   17.4 JPA 305   17.4.1 实体 306   17.4.2 EntityManager 309   17.5 持久化查询语言 313   17.6 常用的JPA注释 316   17.7 小结 318   第18章 Hibernate 319   18.1 Hibernate体系结构 319   18.2 Hibernate核心接口 321   18.3 一个简单的Hibernate例子 321   18.4 详解Hibernate配置文件 325   18.4.1 Hibernate的两种配置方式 325   18.4.2 配置数据库连接池 327   18.5 HQL简介 328   18.6 小结 330   第19章 权限管理系统(Struts+Spring+Hiberante+Ajax) 331   19.1 需求分析 331   19.2 系统总体流程设计 331   19.3 系统设计 332   19.4 系统总体解析 336   19.5 系统功能解析 364   19.5.1 管理员登录 364   19.5.2 模块管理 374   19.5.3 角色数据操作 383   19.5.4 资源操作 391   19.5.5 用户管理 394   19.6 小结 404   第20章 航空订票系统(JSF/Richfaces+EJB+JPA) 405   20.1 需求分析 405   20.2 基本设计理念 406   20.3 系统设计 407   20.3.1 系统用例分析 407   20.3.2 持久化数据分析 413   20.3.3 系统操作序列描述 413   20.3.4 业务接口设计 419   20.4 数据库设计 421   20.4.1 数据库规划 421   20.4.2 具体数据库表 423   20.4.3 SQL代码 426   20.5 系统实现 431   20.5.1 工程开发环境的建立 431   20.5.2 EJB Entity开发 435   20.5.3 EJB Session开发 443   20.5.4 Message-Driven Bean开发 447   20.5.5 JSF/Richfaces开发 448   20.5.6 远程连接 455   20.5.7 系统配置 456   20.6 系统运行 462   20.6.1 服务器的选择 462   20.6.2 系统的部署 462   20.6.3 系统的运行 463   20.7 小结 466

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值